<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2019/11/22
 * Time: 10:16
 */

namespace app\common\model;


class IcmpPing
{
    public function PingIp($host)
    {
        //标识符随便填的,序列号也是随便填的211
        $data='Z'.'F'.chr(0).chr(211);
        //ping程序凑够64byte的报文,这里包括IP首部20byte
        for($i=0;$i<56;$i++){
            $data.=chr(0);
        }
        $startTime=microtime(true);
        $result=$this->sendPackage($host,8,0,$data,function($message)
        {
            global $host;
            global $startTime;
            //按照字节解析成数组
            $message = unpack('C*', $message);
            $seq=$message[28];
            $ttl=$message[9];
            echo $ttl;die;
//            $endTime=microtime(true);
//             echo (count($message)-20)." bytes from $host: icmp_seq=$seq  ttl=$ttl  time=".(round((($endTime-$startTime)*1000),3))." ms".PHP_EOL;
        });
        if($result!=null){
//             echo "Error :$result";
//            return 2;
            echo "Timeout";die;
        }
    }
    /**
     * @param $host string 主机ip
     * @param $type int    icmp报文类型
     * @param $code int    icmp报文代码
     * @param $data string icmp报文数据
     * @param $callbackfunc string 请求完成之后的回调函数,由上层模块决定
     * @description 向主机发送icmp报文
     *
     * icmp 报文头  | 1字节类型 | 1字节代码 | 2字节校验和 |
     */
    private function sendPackage($host,$type,$code,$data,$callbackfunc)
    {
        //icmp错误信息
        $g_icmp_error=null;
        //封装icmp报文
        //icmp头
        $package=chr($type).chr($code);
        $package.=chr(0).chr(0);
        $package.=$data;
        //设置校验和
        $this->setSum($package);
        //发送报文
        $socket=socket_create(AF_INET,SOCK_RAW,getprotobyname('icmp')) or die('Cannot create socket');
        socket_sendto($socket,$package,strlen($package),0,$host,0);
        $read   = array($socket);
        $write  = NULL;
        $except = NULL;
        $select = socket_select($read, $write, $except, 0, 300 * 1000);
        if ($select === NULL)
        {
            $g_icmp_error = "Select Error";
            socket_close($socket);
            return $g_icmp_error;
        }
        elseif ($select === 0)
        {
            $g_icmp_error = "Timeout";
            socket_close($socket);
            return $g_icmp_error;
        }
        socket_recvfrom($socket, $recv, 65535, 0, $host, $port);
        //回调结果处理函数
        call_user_func($callbackfunc,$recv);
        return $g_icmp_error;
    }
    /**
     * @param $data string 报文数据
     * @description 设置icmp报文校验和
     */
    private function setSum(&$data){
        $list=unpack('n*',$data);
        $length=strlen($data);
        $sum=array_sum($list);
        if($length%2){
            $tmp=unpack('C*',$data[$length-1]);
            $sum+=$tmp[1];
        }
        $sum=($sum>>16)+($sum&0xffff);
        $sum+=($sum>>16);
        $r=pack('n*',~$sum);
        $data[2]=$r[0];
        $data[3]=$r[1];
    }


}